home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Aminet 32
/
Aminet 32 (1999)(Schatztruhe)[!][Aug 1999].iso
/
Aminet
/
dev
/
misc
/
unsqsh.lha
/
unsqsh.c
next >
Wrap
C/C++ Source or Header
|
1999-05-31
|
11KB
|
604 lines
/*
portable code to decrunch XPK-SQSH files
written from "xpksqsh.library 1.10 (6.3.94)"
(24.12.97) jah@fh-zwickau.de
tested with sas6.51(m68k) gcc2.7.2(i386) gcc2.7.2(sparc)
(23.01.99) h430827@stud.u-szeged.hu
fixed problem with raw chunks, added checksum verification
tested with egcs-2.91.57(i386)
(31.05.99) wepl@kagi.com
complete reworked, header chksum check added, optimized
tested with xlC3.1.3(ppc) gcc2.7.2(i486) gcc2.8.1(sparc)
*/
/*
#define debug
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define XPKERR_NOXPK 1
#define XPKERR_UNKNOWNCOMP 2
#define XPKERR_FORMAT 3
#define XPKERR_CHKSUM 4
#define XPKERR_UNKNOWNCHUNK 5
typedef unsigned char UBYTE; /* 8 bit */
typedef unsigned short int UWORD; /* 16 bit */
typedef unsigned long int ULONG; /* 32 bit */
volatile int xpkerrno;
static const char *xpkerrtext[] = {
NULL,
"not a XPK file",
"unknown compressor type",
"data format error",
"checksum failed",
"unknown chunk type"
};
/*int xpk_check (UBYTE[16] src, int* srclen, int* dstlen);*/
int xpk_check (UBYTE* src, int* srclen, int* dstlen);
int xpk_unpack (UBYTE* src, UBYTE* dst);
void sqsh (UBYTE* src, UBYTE* dst);
int main(int ac,char *av[]) {
UBYTE *src;
UBYTE *dst;
int srclen;
int dstlen;
int rc=1;
if (! (src = (UBYTE*) malloc(16))) {
fprintf(stderr,"no memory\n");
} else {
if (1 != fread(src,16,1,stdin)) {
perror("error reading source file-header");
} else {
if (! xpk_check(src,&srclen,&dstlen)) {
fprintf(stderr,"%s\n",xpkerrtext[xpkerrno]);
} else {
if (! (src = realloc(src,srclen))) {
fprintf(stderr,"no memory\n");
} else {
if (! (dst = malloc(dstlen))) {
fprintf(stderr,"no memory\n");
} else {
if (1 != fread(src+16,srclen-16,1,stdin)) {
perror("error reading source file");
} else {
if (! xpk_unpack(src,dst)) {
fprintf(stderr,"%s\n",xpkerrtext[xpkerrno]);
} else {
if (1 != fwrite(dst,dstlen,1,stdout)) {
perror("error writing destination file");
} else {
rc = 0;
}
}
}
free(dst);
}
}
}
}
free(src);
}
return rc;
}
/*
* check the given 16 byte array if it is a valid XPK-SQSH header
* and returns source and destination legth
*
*/
int xpk_check (UBYTE* src, int* srclen, int* dstlen) {
if ('X' != *src++ ||
'P' != *src++ ||
'K' != *src++ ||
'F' != *src++) {
xpkerrno = XPKERR_NOXPK;
return 0;
}
*srclen = *src++ << 24;
*srclen |= *src++ << 16;
*srclen |= *src++ << 8;
*srclen |= *src++;
if ('S' != *src++ ||
'Q' != *src++ ||
'S' != *src++ ||
'H' != *src++) {
xpkerrno = XPKERR_UNKNOWNCOMP;
return 0;
}
*dstlen = *src++ << 24;
*dstlen |= *src++ << 16;
*dstlen |= *src++ << 8;
*dstlen |= *src++;
xpkerrno = 0;
return 1;
}
/*
; file header:
; 0 LONG "XPKF"
; 4 LONG file size - 8
; 8 LONG "SQSH"
; 12 LONG unpacked size
; $10 QUAD original file header
; $20 WORD
; $22 WORD
; $24 first chunk
;
; chunk header:
; 0 BYTE type
; 1 BYTE checksum
; 2 WORD checksum
; 4 WORD packed chunk size starting from offset 8, long aligned
; 6 WORD unpacked chunk size
; 8 LABEL bitstream...
*/
int xpk_unpack (UBYTE* src, UBYTE* dst) {
int len; /* unpacked size */
UBYTE type; /* type of chunk */
UBYTE hchk; /* chunk header chksum */
UWORD chk; /* chunk data chksum */
UWORD cp; /* chunk packed length */
UWORD cu; /* chunk unpacked length */
ULONG l, *lp;
#ifdef debug
UBYTE* t=src; /* used for offset calculation */
#endif
src += 12; /* skip id's and file size */
len = *src++ << 24;
len |= *src++ << 16;
len |= *src++ << 8;
len |= *src++;
src += 20; /* skip original file header and ?? */
/* do for each chunk */
while (len) {
type = *src++; /* type of chunk */
hchk = *src++; /* chunk header chksum */
chk = *(UWORD*)src; /* chunk data chksum */
src += 2;
cp = *src++ << 8;
cp |= *src++; /* chunk packed length */
cu = *src++ << 8;
cu |= *src++; /* chunk unpacked length */
#ifdef debug
fprintf(stderr,"offset=%6x type=%02x chk=%04x cp=%04x cu=%04x",src-t,type,chk,cp,cu);
#endif
/* check chunk header chksum */
hchk ^= type;
hchk ^= chk ^ (chk >> 8);
hchk ^= cp ^ (cp >> 8);
hchk ^= cu ^ (cu >> 8);
if (hchk) {
xpkerrno=XPKERR_CHKSUM;
return 0;
}
/* make packed chunk size long aligned */
cp = (cp + 3) & 0xfffc;
/* check chunk data chksum */
for (l=0,lp=(ULONG*)(src+cp); lp!=(ULONG*)src; ) l ^= *--lp;
chk ^= l & 0xffff;
chk ^= l >> 16;
if (chk) {
xpkerrno=XPKERR_CHKSUM;
return 0;
}
/* check chunk type */
switch (type) {
case 0:
/* unpacked */
memcpy(dst,src,cu);
dst += cu;
src += cp;
len -= cu;
continue;
case 1:
/* SQSH packed */
sqsh(src,dst);
dst += cu;
src += cp;
len -= cu;
continue;
default:
/* unknown type */
xpkerrno=XPKERR_UNKNOWNCHUNK;
return 0;
}
}
xpkerrno = 0;
return 1;
}
int bfextu(UBYTE *p,int bo,int bc) {
int r;
p += bo / 8;
r = *(p++);
r <<= 8;
r |= *(p++);
r <<= 8;
r |= *p;
r <<= bo % 8;
r &= 0xffffff;
r >>= 24 - bc;
return r;
}
#define bfextu1 ((*(src + d0 / 8) >> 7 - (d0 % 8)) & 1)
int bfextu3(UBYTE *p,int bo) {
int r;
p += bo / 8;
r = *(p++);
r <<= 8;
r |= *p;
r >>= 13 - (bo % 8);
r &= 7;
return r;
}
int bfexts(UBYTE *p,int bo,int bc) {
int r;
p += bo / 8;
r = *(p++);
r <<= 8;
r |= *(p++);
r <<= 8;
r |= *p;
r <<= (bo % 8) + 8;
r >>= 32 - bc;
return r;
}
void sqsh(UBYTE *src, UBYTE *dst) {
int d0,d1,d2,d3,d4,d5,d6,a2,a5;
UBYTE *a4,*a6;
UBYTE a3[] = { 2,3,4,5,6,7,8,0,3,2,4,5,6,7,8,0,4,3,5,2,6,7,8,0,5,4,
6,2,3,7,8,0,6,5,7,2,3,4,8,0,7,6,8,2,3,4,5,0,8,7,6,2,3,4,5,0 };
#ifdef debug
fprintf(stderr,"=%02x%02x dst=%x",*src,*(src+1),dst);
#endif
a6 = dst;
a6 += *src++ << 8;
a6 += *src++;
d0 = d1 = d2 = d3 = a2 = 0;
d3 = *(src++);
*(dst++) = d3;
l6c6: if (d1 >= 8) goto l6dc;
if (bfextu1) goto l75a;
d0 ++;
d5 = 0;
d6 = 8;
goto l734;
l6dc: if (bfextu1) goto l726;
d0 ++;
if (! bfextu1) goto l75a;
d0 ++;
if (bfextu1) goto l6f6;
d6 = 2;
goto l708;
l6f6: d0 ++;
if (! bfextu1) goto l706;
d6 = bfextu3(src,d0);
d0 += 3;
goto l70a;
l706: d6 = 3;
l708: d0 ++;
l70a: d6 = *(a3 + (8*a2) + d6 - 17);
if (d6 != 8) goto l730;
l718: if (d2 < 20) goto l722;
d5 = 1;
goto l732;
l722: d5 = 0;
goto l734;
l726: d0 += 1;
d6 = 8;
if (d6 == a2) goto l718;
d6 = a2;
l730: d5 = 4;
l732: d2 += 8;
l734: d4 = bfexts(src,d0,d6);
d0 += d6;
d3 -= d4;
*dst++ = d3;
d5--;
if (d5 != -1) goto l734;
if (d1 == 31) goto l74a;
d1 += 1;
l74a: a2 = d6;
l74c: d6 = d2;
d6 >>= 3;
d2 -= d6;
if (dst < a6) goto l6c6;
#ifdef debug
fprintf(stderr," dst=%p a6=%p d0=8*%x+%d->%x\n",dst,a6,d0/8,d0%8,(d0+7)/8+3);
/* fprintf(stderr,"d1=%x d2=%x d3=%x d4=%x d5=%x d6=%x a2=%x a4=%x a5=%x\n",d1,d2,d3,d4,d5,d6,a2,a4,a5); */
#endif
return;
l75a: d0++;
if (bfextu1) goto l766;
d4 = 2;
goto l79e;
l766: d0++;
if (bfextu1) goto l772;
d4 = 4;
goto l79e;
l772: d0++;
if (bfextu1) goto l77e;
d4 = 6;
goto l79e;
l77e: d0++;
if (bfextu1) goto l792;
d0++;
d6 = bfextu3(src,d0);
d0 += 3;
d6 += 8;
goto l7a8;
l792: d0++;
d6 = bfextu(src,d0,5);
d0 += 5;
d4 = 16;
goto l7a6;
l79e: d0++;
d6 = bfextu1;
d0 ++;
l7a6: d6 += d4;
l7a8: if (bfextu1) goto l7c4;
d0 ++;
if (bfextu1) goto l7bc;
d5 = 8;
a5 = 0;
goto l7ca;
l7bc: d5 = 14;
a5 = -0x1100;
goto l7ca;
l7c4: d5 = 12;
a5 = -0x100;
l7ca: d0++;
d4 = bfextu(src,d0,d5);
d0 += d5;
d6 -= 3;
if (d6 < 0) goto l7e0;
if (d6 == 0) goto l7da;
d1 -= 1;
l7da: d1 -= 1;
if (d1 >= 0) goto l7e0;
d1 = 0;
l7e0: d6 += 2;
a4 = -1 + dst + a5 - d4;
l7ex: *dst++ = *a4++;
d6--;
if (d6 != -1) goto l7ex;
d3 = *(--a4);
goto l74c;
}
/*
Unpack move.l a6,-(sp)
movea.l a0,a6
movea.l (a6),a0 xsp_InBuf
movea.l (8,a6),a1 xsp_OutBuf
moveq #0,d7
move.w (a0)+,d7
move.l d7,($10,a6)
bsr.b lbc0006b0
moveq #0,d0
movea.l (sp)+,a6
rts
lbc0006b0 movea.l a1,a6
adda.l d7,a6
moveq #0,d0
moveq #0,d1
moveq #0,d2
moveq #0,d3
suba.w a2,a2
lea (data_a3,pc),a3
move.b (a0)+,d3
move.b d3,(a1)+
lbc0006c6 cmp.w #8,d1
bcc.b lbc0006dc
bftst (a0){d0:1}
bne.w lbc00075a
addq.l #1,d0
moveq #0,d5
moveq #8,d6
bra.b lbc000734
lbc0006dc bftst (a0){d0:1}
bne.b lbc000726
addq.l #1,d0
bftst (a0){d0:1}
beq.b lbc00075a
addq.l #1,d0
bftst (a0){d0:1}
bne.b lbc0006f6
moveq #2,d6
bra.b lbc000708
lbc0006f6 addq.l #1,d0
bftst (a0){d0:1}
beq.b lbc000706
bfextu (a0){d0:3},d6
addq.l #3,d0
bra.b lbc00070a
lbc000706 moveq #3,d6
lbc000708 addq.l #1,d0
lbc00070a lea (-$10,a3,a2.w*8),a4
move.b (-1,a4,d6.w),d6
cmp.w #8,d6
bne.b lbc000730
lbc000718 cmp.w #$14,d2
bcs.b lbc000722
moveq #1,d5
bra.b lbc000732
lbc000722 moveq #0,d5
bra.b lbc000734
lbc000726 addq.l #1,d0
moveq #8,d6
cmpa.w d6,a2
beq.b lbc000718
move.l a2,d6
lbc000730 moveq #4,d5
lbc000732 addq.w #8,d2
lbc000734 bfexts (a0){d0:d6},d4
add.l d6,d0
sub.b d4,d3
move.b d3,(a1)+
dbra d5,lbc000734
cmp.w #$1f,d1
beq.b lbc00074a
addq.w #1,d1
lbc00074a movea.w d6,a2
lbc00074c move.w d2,d6
lsr.w #3,d6
sub.w d6,d2
cmpa.l a6,a1
blt.w lbc0006c6
rts
lbc00075a addq.l #1,d0
bftst (a0){d0:1}
bne.b lbc000766
moveq #2,d4
bra.b lbc00079e
lbc000766 addq.l #1,d0
bftst (a0){d0:1}
bne.b lbc000772
moveq #4,d4
bra.b lbc00079e
lbc000772 addq.l #1,d0
bftst (a0){d0:1}
bne.b lbc00077e
moveq #6,d4
bra.b lbc00079e
lbc00077e addq.l #1,d0
bftst (a0){d0:1}
bne.b lbc000792
addq.l #1,d0
bfextu (a0){d0:3},d6
addq.l #3,d0
addq.l #8,d6
bra.b lbc0007a8
lbc000792 addq.l #1,d0
bfextu (a0){d0:5},d6
addq.l #5,d0
moveq #$10,d4
bra.b lbc0007a6
lbc00079e addq.l #1,d0
bfextu (a0){d0:1},d6
addq.l #1,d0
lbc0007a6 add.w d4,d6
lbc0007a8 bftst (a0){d0:1}
bne.b lbc0007c4
addq.l #1,d0
bftst (a0){d0:1}
bne.b lbc0007bc
moveq #8,d5
suba.w a5,a5
bra.b lbc0007ca
lbc0007bc moveq #14,d5
movea.w #$ef00,a5
bra.b lbc0007ca
lbc0007c4 moveq #12,d5
movea.w #$ff00,a5
lbc0007ca addq.l #1,d0
bfextu (a0){d0:d5},d4
add.l d5,d0
subq.w #3,d6
bcs.b lbc0007e0
beq.b lbc0007da
subq.w #1,d1
lbc0007da subq.w #1,d1
bge.b lbc0007e0
moveq #0,d1
lbc0007e0 addq.w #2,d6
lea (-1,a1,a5.w),a4
suba.w d4,a4
lsr.w #1,d6
bcc.b lbc0007ee
lbc0007ec move.b (a4)+,(a1)+
lbc0007ee move.b (a4)+,(a1)+
dbra d6,lbc0007ec
move.b -(a4),d3
bra.w lbc00074c
data_a3 dc.l $2030405
dc.l $6070800
dc.l $3020405
dc.l $6070800
dc.l $4030502
dc.l $6070800
dc.l $5040602
dc.l $3070800
dc.l $6050702
dc.l $3040800
dc.l $7060802
dc.l $3040500
dc.l $8070602
dc.l $3040500
dc.b 0
dc.b 0
*/